' matrix2d - 2D Matrix type and related functions
' written by the Math Wizard
' March 2009

Type Matrix2D
    As Double       a, b, c, _          ' Matrix elements
                    d, e, f, _
                    g, h, i
    Declare Constructor( _
        ByVal a As Double = 1, ByVal b As Double = 0, _
        ByVal c As Double = 0, ByVal d As Double = 0, _
        ByVal e As Double = 1, ByVal f As Double = 0, _
        ByVal g As Double = 0, ByVal h As Double = 0, _
        ByVal i As Double = 1 _
    )
End Type

Declare Function SinL(ByVal t As Integer) As Double
Declare Function CosL(ByVal t As Integer) As Double
Declare Function MShift(ByVal x As Double, ByVal y As Double) As Matrix2D
Declare Function MScale(ByVal x As Double, ByVal y As Double) As Matrix2D
Declare Function MRotate(ByVal t As Integer) As Matrix2D

Const As Double PI = 3.1415926535897932



Function SinL(ByVal t As Integer) As Double
' A sine function by lookup.
' The first time it is called, build the lookup table
' (better if it is called before it is needed).

Static s(0 To 359) As Double
Static lookupbuilt As Integer
Dim As Integer i                    ' counter variable

If t > 359 Then t Mod= 360
If lookupbuilt = 2 Then
    Return s(t)
Else
    For i = 0 To 359
        s(i) = Sin(i * PI / 180)
    Next i
    lookupbuilt = 2
    Return s(t)
End If

End Function

Function CosL(ByVal t As Integer) As Double
' A cosine function by lookup.
' The first time it is called, build the lookup table
' (better if it is called before it is needed).

Static c(0 To 359) As Double
Static lookupbuilt As Integer
Dim As Integer i                    ' counter variable

If lookupbuilt = 2 Then
    Return c(t)
Else
    For i = 0 To 359
        c(i) = Cos(i * PI / 180)
    Next i
    lookupbuilt = 2
    Return c(t)
End If

End Function

Constructor Matrix2D( _
    ByVal a As Double = 1, ByVal b As Double = 0, ByVal c As Double = 0, _
    ByVal d As Double = 0, ByVal e As Double = 1, ByVal f As Double = 0, _
    ByVal g As Double = 0, ByVal h As Double = 0, ByVal i As Double = 1 _
)

' The default values represent an identity matrix.

With This
    .a = a : .b = b : .c = c
    .d = d : .e = e : .f = f
    .g = g : .h = h : .i = i
End With

End Constructor

' Overloaded operators: + and *

Operator +( _
    ByRef   lhs     As Matrix2D, _
    ByRef   rhs     As Matrix2D _
) As Matrix2D
' Add two matrices together, but do it
' so that we can use the "+" operator in the natural way.

Return Type<Matrix2D>( _
    lhs.a + rhs.a, lhs.b + rhs.b, lhs.c + rhs.c, _
    lhs.d + rhs.d, lhs.e + rhs.e, lhs.f + rhs.f, _
    lhs.g + rhs.g, lhs.h + rhs.h, lhs.i + rhs.i _
)

End Operator


Operator *( _
    ByRef   lhs     As Matrix2D, _
    ByRef   rhs     As Matrix2D _
) As Matrix2D
' Multiply two matrices together, but do it
' so that we can use the "*" operator in the natural way.
' Each line below is the dot product of the corresponding
' lhs-row and rhs-column.

Return Type<Matrix2D>( _
    (lhs.a * rhs.a + lhs.b * rhs.d + lhs.c * rhs.g), _
    (lhs.a * rhs.b + lhs.b * rhs.e + lhs.c * rhs.h), _
    (lhs.a * rhs.c + lhs.b * rhs.f + lhs.c * rhs.i), _
    (lhs.d * rhs.a + lhs.e * rhs.d + lhs.f * rhs.g), _
    (lhs.d * rhs.b + lhs.e * rhs.e + lhs.f * rhs.h), _
    (lhs.d * rhs.c + lhs.e * rhs.f + lhs.f * rhs.i), _
    (lhs.g * rhs.a + lhs.h * rhs.d + lhs.i * rhs.g), _
    (lhs.g * rhs.b + lhs.h * rhs.e + lhs.i * rhs.h), _
    (lhs.g * rhs.c + lhs.h * rhs.f + lhs.i * rhs.i) _
)

End Operator

Function MShift(ByVal x As Double, ByVal y As Double) As Matrix2D
' creates a translation linear transformation

Return Type<Matrix2D>( _
    1, 0, x, _
    0, 1, y, _
    0, 0, 1 _
)

End Function

Function MScale(ByVal x As Double, ByVal y As Double) As Matrix2D
' creates a scaling linear transformation

Return Type<Matrix2D>( _
    x, 0, 0, _
    0, y, 0, _
    0, 0, 1 _
)

End Function

Function MRotate(ByVal t As Integer) As Matrix2D
' create a rotation linear transformation

Return Type<Matrix2D>( _
    CosL(t), -SinL(t), 0, _
    SinL(t), CosL(t), 0, _
    0, 0, 1 _
)
    
End Function
